package com.sc.nft.admin.rpc;

import com.sc.nft.pool.UserPool;
import org.apache.commons.lang3.StringUtils;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sc.nft.admin.request.*;
import com.sc.nft.dao.DigitalCollectionDao;
import com.sc.nft.dao.UserCreatorInfoDao;
import com.sc.nft.dao.UserInfoDao;
import com.sc.nft.dto.CirculateDetailsDTO;
import com.sc.nft.dto.DigitalCollectionDTO;
import com.sc.nft.dto.SimpleDigitalCollectionDTO;
import com.sc.nft.dto.SimpleDigitalGetSeparateFundDTO;
import com.sc.nft.entity.DigitalCollection;
import com.sc.nft.entity.UserCreatorInfo;
import com.sc.nft.entity.UserInfo;
import com.sc.nft.entity.req.CollectionGiveDaoBatchRequest;
import com.sc.nft.entity.req.CollectionGiveDaoRequest;
import com.sc.nft.entity.req.DaoCollectionGiveLogPageRequest;
import com.sc.nft.entity.req.DaoCollectionGiveRequest;
import com.sc.nft.entity.vo.CollectionSimpleVO;
import com.sc.nft.entity.vo.GetDaoCollectionGiveLogPageVO;
import com.sc.nft.entity.vo.SaasTaskDetailsCollectionVO;
import com.sc.nft.enums.RedisKeyEnum;
import com.sc.nft.service.*;
import com.sc.nft.sup.ErrorCode;
import com.sc.nft.sup.PageResult;
import com.sc.nft.sup.Result;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.annotations.ApiIgnore;

import javax.validation.Valid;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Slf4j
@RequiredArgsConstructor
@RestController
@RequestMapping("/rpc/collection")
@Api(tags = "后台藏品RPC接口")
public class DigitalCollectionRpc {

    private final DigitalCollectionDao digitalCollectionDao;
    private final DigitalCollectionService digitalCollectionService;
    private final RedisTemplate redisTemplate;
    private final UserCreatorInfoDao userCreatorInfoDao;
    private final SmsCodeRecordService smsCodeRecordService;
    private final UserCollectionService userCollectionService;
    private final DaoCollectionGiveLogService daoCollectionGiveLogService;
    private final UserInfoDao userInfoDao;
    private final Redisson redisson;
    @PostMapping(value = "/simpleList", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiOperation(value = "藏品列表", notes = "藏品列表", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiIgnore
    public PageResult<SimpleDigitalCollectionDTO> simpleList(@Valid @RequestBody IdPageRequest id) {
        return PageResult.success(digitalCollectionDao.simpleList(id.getId(),id.toMp()).convert(digitalCollection -> {
            SimpleDigitalCollectionDTO dto = new SimpleDigitalCollectionDTO();
            dto.setId(digitalCollection.getId());
            dto.setName(digitalCollection.getFirstTitle());
            dto.setCreationContent(digitalCollection.getCreationContent());
            dto.setSumCount(digitalCollection.getSumCount());
            dto.setContractAddress(digitalCollection.getContractAddress());
            dto.setIssuePrice(digitalCollection.getIssuePrice());
            dto.setCreateTime(digitalCollection.getCreateTime());
            return dto;
        }));
    }


    @PostMapping(value = "/simpleSearchList", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiOperation(value = "搜索藏品列表", notes = "藏品列表", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiIgnore
    public PageResult<SimpleDigitalCollectionDTO> simpleSearchList(@Valid @RequestBody SarchCollectionPageRequest request) {
        return PageResult.success(digitalCollectionDao.simpleSearchList(request.getId(),request.getCollectionName(),request.toMp()).convert(digitalCollection -> {
            SimpleDigitalCollectionDTO dto = new SimpleDigitalCollectionDTO();
            dto.setId(digitalCollection.getId());
            dto.setName(digitalCollection.getFirstTitle());
            dto.setCreationContent(digitalCollection.getCreationContent());
            dto.setSumCount(digitalCollection.getSumCount());
            dto.setContractAddress(digitalCollection.getContractAddress());
            dto.setIssuePrice(digitalCollection.getIssuePrice());
            dto.setCreateTime(digitalCollection.getCreateTime());
            return dto;
        }));
    }


    @PostMapping(value = "/getEcologyCollection", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiOperation(value = "获取生态藏品接口", notes = "藏品列表", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiIgnore
    public PageResult<SimpleDigitalCollectionDTO> getEcologyCollection(@Valid @RequestBody SarchCollectionPageRequest request) {
        return PageResult.success(digitalCollectionDao.getEcologyCollection(request.getId(),request.getCollectionName(),request.toMp()));
    }


    @PostMapping(value = "/detail", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiOperation(value = "藏品详情", notes = "藏品详情", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiIgnore
    public Result<DigitalCollectionDTO>  detail(@Valid @RequestBody IdRequest request) {
        DigitalCollection digitalCollection = digitalCollectionDao.getById(request.getId());
        return Result.success(digitalCollection,DigitalCollectionDTO.class);
    }

    @PostMapping(value = "/getCollectionSimplenessByIds", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiOperation(value = "根据ids获取对应的藏品信息", notes = "根据ids获取对应的藏品信息", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiIgnore
    public Result<List<SaasTaskDetailsCollectionVO>>  getCollectionSimplenessByIds(@Valid @RequestBody List<Long> ids) {
        return Result.success(digitalCollectionDao.getCollectionSimplenessByIds(ids));
    }
    @PostMapping(value = "/collectionSimpleList", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiOperation(value = "简单藏品列表", notes = "简单藏品列表", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    public Result<List<CollectionSimpleVO>> editCollection(@Valid @RequestBody ListDigitalCollectionRequest request) {
        return Result.successColl(digitalCollectionService.simpleList(request.getFirstTitle(),request.getUserCreatorId()), CollectionSimpleVO.class);
    }

    @PostMapping(value = "/collectionSimpleListPage", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiOperation(value = "简单藏品列表(分页)", notes = "简单藏品列表", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    public PageResult<CollectionSimpleVO> collectionSimpleListPage(@Valid @RequestBody ListDigitalCollectionRequest request) {
        return PageResult.success(digitalCollectionService.collectionSimpleListPage(request.getFirstTitle(),request.getUserCreatorId()
                ,request.toMp(),request.getTypeEnum()), CollectionSimpleVO.class);
    }


    @PostMapping(value = "/circulateDetails", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiOperation(value = "流转详情", notes = "流转详情", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiIgnore
    public Result<CirculateDetailsDTO>  circulateDetails(@Valid @RequestBody IdRequest request) {
        return Result.success(digitalCollectionService.circulateDetails(request.getId()));
    }

    @PostMapping(value = "/getDaoSeparateFund", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiOperation(value = "获取给本dao分过账的数据", notes = "自由市场挂单", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    List<SimpleDigitalGetSeparateFundDTO> getDaoSeparateFund(@Valid @RequestBody IdRequest idRequest){
        return digitalCollectionService.getDaoSeparateFund(idRequest.getId());
    }


    @ApiOperation(value = "dao藏品转增", notes = "dao藏品转增", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/collectionGiveDao", produces = MediaType.APPLICATION_JSON_VALUE)
    public Result collectionGiveDao(@Valid @RequestBody CollectionGiveDaoRequest request) {
        if(StrUtil.isBlank(request.getVerifyCode())){
            return Result.fail(ErrorCode.VERIFICATION_ERROR);
        }
        UserCreatorInfo userCreatorInfo = userCreatorInfoDao.getById(request.getDaoId());
        if(StringUtils.isBlank(userCreatorInfo.getPhoneNo())){
            return Result.fail("未设置验证手机号");
        }
//        UserInfo userInfo = userInfoDao.getById(userCreatorInfo.getUserId());
        Object errorTime = redisTemplate.opsForValue().get(RedisKeyEnum.COLLECTION_GIVE_DAO_CODE_ERROR_TIME.getKey() + request.getReceiveUserTel());
        if(errorTime!=null&&Integer.parseInt(String.valueOf(errorTime))>5){
            return Result.fail("尝试次数过多，请十分钟后再试");
        }
        Object code = redisTemplate.opsForValue().get(RedisKeyEnum.COLLECTION_GIVE_DAO_CODE.getKey() + request.getReceiveUserTel());
        if(!StrUtil.equals(request.getVerifyCode(),String.valueOf(code))){
            redisTemplate.opsForValue().increment(RedisKeyEnum.COLLECTION_GIVE_DAO_CODE_ERROR_TIME.getKey() + request.getReceiveUserTel());
            redisTemplate.expire(RedisKeyEnum.COLLECTION_GIVE_DAO_CODE_ERROR_TIME.getKey() + request.getReceiveUserTel(),10L, TimeUnit.MINUTES);
            return Result.fail(ErrorCode.VERIFICATION_ERROR);
        }
        request.setUserInfo(UserPool.getUser());
        RLock lock = redisson.getLock(RedisKeyEnum.TRANSFER_LOCK.getKey() + request.getId());
        try{
              boolean res = lock.tryLock(10, TimeUnit.SECONDS);
              if (!res) {
                  return Result.fail("请勿重复提交");
              }
            userCollectionService.collectionGiveDao(request);
        }catch (InterruptedException e) {
            return Result.fail("赠送失败");
        }finally {
           if (lock.isLocked()) {
               lock.unlock();
           }
            redisTemplate.delete(RedisKeyEnum.COLLECTION_GIVE_DAO.getKey()+request.getReceiveUserTel());
        }

        return Result.success();
    }

    @ApiOperation(value = "dao藏品转增", notes = "dao藏品转增", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/collectionBatchGiveDao", produces = MediaType.APPLICATION_JSON_VALUE)
    public Result collectionBatchGiveDao(@Valid @RequestBody CollectionGiveDaoBatchRequest request) {
        if(StrUtil.isBlank(request.getVerifyCode())){
            return Result.fail(ErrorCode.VERIFICATION_ERROR);
        }
        Object errorTime = redisTemplate.opsForValue().get(RedisKeyEnum.COLLECTION_GIVE_DAO_CODE_ERROR_TIME.getKey() + request.getReceiveUserTel());
        if(errorTime!=null&&Integer.parseInt(String.valueOf(errorTime))>5){
            return Result.fail("尝试次数过多，请十分钟后再试");
        }
        Object code = redisTemplate.opsForValue().get(RedisKeyEnum.COLLECTION_GIVE_DAO_CODE.getKey() + request.getReceiveUserTel());
        if(!StrUtil.equals(request.getVerifyCode(),String.valueOf(code))){
            redisTemplate.opsForValue().increment(RedisKeyEnum.COLLECTION_GIVE_DAO_CODE_ERROR_TIME.getKey() + request.getReceiveUserTel());
            redisTemplate.expire(RedisKeyEnum.COLLECTION_GIVE_DAO_CODE_ERROR_TIME.getKey() + request.getReceiveUserTel(),10L, TimeUnit.MINUTES);
            return Result.fail(ErrorCode.VERIFICATION_ERROR);
        }

        List<RLock>locks=new ArrayList<>();
        List<Long> collectionIdList = request.getIdList();
        request.setUserInfo(UserPool.getUser());
        try{
            for (Long id : collectionIdList) {
                RLock lock = redisson.getLock(RedisKeyEnum.TRANSFER_LOCK.getKey() + id);
                locks.add(lock);
                boolean res = lock.tryLock(10, TimeUnit.SECONDS);
                if (!res) {
                    return Result.fail("请勿重复提交");
                }
            }
            userCollectionService.collectionBatchGiveDao(request);
        }catch (InterruptedException e) {
            return Result.fail("赠送失败");
        }finally {
            locks.forEach(rLock -> {
                if (rLock.isLocked()) {
                    rLock.unlock();
                }
            });
            redisTemplate.delete(RedisKeyEnum.COLLECTION_GIVE_DAO.getKey()+request.getReceiveUserTel());
        }
        return Result.success();
    }



    @ApiOperation(value = "获取转增验证码", notes = "获取转增验证码", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @PostMapping(value = "/getGiveSms", produces = MediaType.APPLICATION_JSON_VALUE)
    public Result getCollectionGiveSms(@Valid @RequestBody DaoCollectionGiveRequest request) {

        if(redisTemplate.hasKey(RedisKeyEnum.COLLECTION_GIVE_DAO.getKey()+request.getUserTel())){
            return Result.fail(ErrorCode.SMS_ONE_MINUTE);
        }
        int code = RandomUtil.randomInt(100000, 999999);
        if(!smsCodeRecordService.sendTemplate(request.getUserTel(),"2231922",new String[]{String.valueOf(code)})){
            return Result.fail(ErrorCode.SMS_FAIL);
        }
        redisTemplate.opsForValue().set(RedisKeyEnum.COLLECTION_GIVE_DAO.getKey()+request.getUserTel(),"1",60L,TimeUnit.SECONDS);
        redisTemplate.opsForValue().set(RedisKeyEnum.COLLECTION_GIVE_DAO_CODE.getKey()+request.getUserTel(),String.valueOf(code),60L,TimeUnit.SECONDS);

        return Result.success();
    }
    @PostMapping(value = "/getDaoCollectionGiveLogPage", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiOperation(value = "dao转增记录", notes = "dao转增记录", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    public PageResult<GetDaoCollectionGiveLogPageVO> getDaoCollectionGiveLogPage(@Valid @RequestBody DaoCollectionGiveLogPageRequest request) {
        Page<GetDaoCollectionGiveLogPageVO> daoCollectionGiveLogPage = daoCollectionGiveLogService.getDaoCollectionGiveLogPage(request);
        List<GetDaoCollectionGiveLogPageVO> records = daoCollectionGiveLogPage.getRecords();
        for (GetDaoCollectionGiveLogPageVO record : records) {
            UserInfo byId = userInfoDao.getById(record.getOperatorId());
            record.setOperator(byId.getNickName());
        }
        return PageResult.success(daoCollectionGiveLogPage);
    }

}
